package com.guchenbo.example.thread;

import com.guchenbo.example.lock.WaitClientCloseServer;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockDemo {

    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 1000, TimeUnit.MILLISECONDS,
                    new ArrayBlockingQueue<>(10));

    public static void main(String[] args) throws InterruptedException {
        //                reentrantLock();
        //                oneReentrantLock();
        reentrantLock2();
        //        reentrantReadWriteLock();
        //        reentrantReadWriteLock2();
    }

    private static void reentrantLock2() {
        ReentrantLock lock = new ReentrantLock(true);
        lock.lock();
        lock.unlock();

        CountDownLatch latch = new CountDownLatch(2);
        for (int i = 0; i < 2; i++) {
            threadPoolExecutor.submit(()->{
                lock.lock();
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                lock.unlock();
                latch.countDown();
            });
        } try {
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        lock.lock();
        lock.unlock();
    }

    private static void reentrantReadWriteLock2() throws InterruptedException {

        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock lockR = lock.readLock();
        ReentrantReadWriteLock.WriteLock lockW = lock.writeLock();
        ExecutorService executorService = Executors.newFixedThreadPool(15);
        for (int i = 0; i < 5; i++) {
            executorService.submit(() -> {
                if (new Random().nextBoolean()) {

                    lockW.lock();
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } finally {
                        //                        lockW.unlock();
                    }
                } else {
                    lockR.lock();
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } finally {
                        //                        lockR.unlock();
                    }
                }
            });
        }
        Thread.sleep(5000);
        System.out.println(lockR);
    }

    private static void oneReentrantLock() {
        ReentrantLock lock = new ReentrantLock(true);

        for (int i = 0; i < 3; i++) {
            threadPoolExecutor.submit(() -> {
                lock.lock();

            });
        }
    }

    static final int SHARED_SHIFT = 16;
    static final int SHARED_UNIT = (1 << SHARED_SHIFT);
    static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

    /**
     * Returns the number of shared holds represented in count
     */
    static int sharedCount(int c) {
        return c >>> SHARED_SHIFT;
    }

    /**
     * Returns the number of exclusive holds represented in count
     */
    static int exclusiveCount(int c) {
        return c & EXCLUSIVE_MASK;
    }

    private static void reentrantReadWriteLock() {

        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock lockR = lock.readLock();
        ReentrantReadWriteLock.WriteLock lockW = lock.writeLock();
        //        lockW.newCondition().await();

        //        threadPoolExecutor.submit(()->{
        //            try {
        //                lockR.lock();
        //                System.out.println("lock");
        //                Thread.sleep(3000);
        //            } catch (InterruptedException e) {
        //                throw new RuntimeException(e);
        //            } finally {
        //                lockR.unlock();
        //            }
        //        });
        for (int i = 0; i < 3; i++) {
            final int finalI = i;
            threadPoolExecutor.submit(() -> {

                try {
                    //                    lockW.lock();
                    lockR.lock();
                    System.out.println("start");
                    //                    new WaitClientCloseServer().start(10000 + finalI);

                    //                    System.out.println("lock");
                    Thread.sleep(3000);
                    //                    lockW.lock();
                    //                    System.out.println("re lock");
                    //                    lockW.unlock();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    lockR.unlock();
                }

            });
        }
    }

    private static void reentrantLock() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        for (int i = 0; i < 3; i++) {
            final int finalI = i;
            threadPoolExecutor.execute(() -> {
                try {
                    lock.lockInterruptibly();
                    //                    lock.lock();
                    new WaitClientCloseServer().start(10000 + finalI);
                    lock.unlock();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                }

            });
        }

        Thread.sleep(5000);

        threadPoolExecutor.shutdownNow();
    }
}
